1. 类型别名

    有两种方法可以定义类型别名:

    1
    2
    typedef double wages;  // wages 是 double 的同义词
    typedef wages *p; // p 是 double* 的同义词

    新标准规定了一种新的方法:

    1
    using SI = Sales_item;  // SI 是 Sales_item 的同义词

    类型别名和类型名等价,只要是类型的名字能出现的地方,就能使用类型别名

    如果某个类型别名指代的是复合类型或常量,那么把它用在声明语句里就会产生意想不到的后果:

    1
    2
    3
    4
    typedef char *pstring;
    const pstring cstr = 0; // cstr 是指向 char 的常量指针
    const pstring *ps; // ps 是一个指针,它的对象是一个指向 char 的常量指针
    const char *cstr = 0; // 是对 const pstring cstr = 0 的错误理解
  2. auto 类型说明符

    C++ 新标准引入了 auto 类型说明符,用它就能让编译器替我们去分析表达式所属的类型,使用 auto 也能在一条语句中声明多个变量,因为一条声明语句只能有一个基本数据类型,所以语句中所有变量的初始基本数据类型都必须一样:

    1
    2
    3
    4
    auto i = 0, *p = &i;  // 正确,i 是整数,p 是整型指针
    auto sz = 0, pi = 3.14; // 错误,sz 和 pi 的类型不一致
    int i = 0, &r = i;
    auto a = r; // a 是一个整数,当引用被用作初始值时,真正参与初始化的其实是引用对象的值

    auto 一般会忽略掉顶层 const,同时底层 const 则会保留下来:

    1
    2
    3
    4
    5
    const int ci = i, &cr = ci;
    auto b = ci; // b 是一个整数(ci 的顶层 const 特性被忽略掉了)
    auto c = cr; // c 是一个整数
    auto d = &i; // d 是一个整型指针
    auto e = &ci; // e 是一个指向整数常量的指针(对常量对象取地址是一种底层 const )

    如果希望推断出的 auto 类型是一个顶层 const,需要明确指出:

    1
    const auto f = ci;    // ci 的推演类型是 int, f 是 const int

    还可以将引用的类型设为 auto,此时原来的初始化规则仍然适用:

    1
    2
    3
    auto &g = ci;  // g  是一个整型常量引用,绑定到 ci
    auto &h = 42; // 错误,不能为非常量引用绑定字面值
    const auto &j = 42; // 正确,可以为常量引用绑定字面值

    要在一条语句中定义多个变量,切记,符号 &* 只从属于某个声明符,而非基本数据类型的一部分,因此初始值必须是同一种类型:

    1
    2
    3
    auto k = ci, &l = i;  // k 是整数,l 是整型引用
    auto &m = ci, *p = &ci; // m 是对整型常量的引用,p 是指向整型常量的指针
    auto &n = i, *p2 = &ci; // 错误,i 的类型是 int 而 &ci 的类型是 const int
  3. decltype 类型指示符

    C++11 新标准引入了 decltype,它的作用是选择并返回操作数的数据类型,但并不实际计算表达式的值,如果使用的表达式是一个变量,则 decltype 返回该变量的类型(包括顶层 const 和引用在内):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    const int ci = 0, &cj = ci;
    decltype(ci) x = 0; // x 的类型是 const int
    decltype(cj) y = x; // y 的类型是 const int&,y 绑定到变量 x
    decltype(cj) z; // 错误,z 是一个引用,必须初始化


    int i = 42, *p = &i, &r = i;
    decltype(r + 0) b; // 正确,加法的结果是 int
    decltype(r) b; // 结果是引用类型
    decltype(*p) c; // 错误,c 是 int&,必须初始化

    如果表达式的内容是解引用操作,则 decltype 将得到引用类型,如上面的 decltype(*p) c;c 就是一个引用类型decltype 的结果与表达式的形式密切相关,对于 decltype 所用的表达式来说,如果变量名加上了一对括号,则得到的类型与不加括号时有所不同:

    1
    2
    3
    // decltype 的表达式如果是加上了括号的变量,结果将是引用
    decltype((i)) d; // 错误,d 是 int&,必须初始化
    decltype(i) e; // 正确,e 是一个未初始化的 int

    切记:decltype((variable))(注意是双层括号)的结果永远是引用,而 decltype(variable)结果只有当 variable 本身就是一个引用时才是引用。